package com.hexb.smh.controller.management;

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.hexb.core.utils.Assert;
import com.hexb.smh.annotations.AopLoginLog;
import com.hexb.smh.annotations.SecretIn;
import com.hexb.smh.config.TranslucentProducer;
import com.hexb.smh.entity.Account;
import com.hexb.smh.entity.enums.LoginType;
import com.hexb.smh.entity.enums.RoleType;
import com.hexb.smh.entity.param.account.ActivePasswordParam;
import com.hexb.smh.entity.param.account.LoginParam;
import com.hexb.smh.entity.param.account.PasswordModifierParam;
import com.hexb.smh.entity.shiro.SmhUsernamePasswordToken;
import com.hexb.smh.errors.ErrorCodes;
import com.hexb.smh.service.IAccountService;
import com.hexb.smh.service.IOperationLogService;
import com.hexb.smh.utils.AccountHelper;
import com.hexb.smh.utils.HttpUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;

import static com.hexb.smh.utils.SmhConstant.*;

/**
 * @author : hexb
 */
@RestController
@RequestMapping("/management")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Api(value = "A1.后台授权", description = "Server", tags = {"A1.后台授权"})
@Slf4j
public class AuthController {

    @NonNull
    final private IAccountService accountService;

    @NonNull
    final private TranslucentProducer translucentProducer;

    @NonNull
    final private IOperationLogService operationLogService;

    @AopLoginLog(type = LoginType.login)
    @ApiOperation(value = "管理员登录")
    @PostMapping("/login")
    @SecretIn
    public Account adminLogin(@RequestBody @Valid LoginParam param, HttpServletRequest request) {
        Object sessionCode = request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        //tag:开发期间不检查
//        Assert.isNull(sessionCode, ErrorCodes.REFRESH_VERIFICATION_CODE);
//        Assert.isEmpty(String.valueOf(sessionCode), ErrorCodes.REFRESH_VERIFICATION_CODE);
        Assert.notEqual(sessionCode, param.getVerificationCode(), ErrorCodes.INVALID_VERIFICATION_CODE);
        Subject subject = SecurityUtils.getSubject();
        SmhUsernamePasswordToken upt = new SmhUsernamePasswordToken(param.getLoginName(), param.getRawPassword());
        upt.setRole(RoleType.admin);
        subject.login(upt);
        String ip = HttpUtils.getRequestIp(request);
        Account account = AccountHelper.getAccount();
        account.setLastLoginIp(ip);
        accountService.loginLog(account.getId(), ip);
        return account;
    }

    @AopLoginLog(type = LoginType.logout)
    @ApiOperation(value = "退出登录")
    @PostMapping("/logout")
    @RequiresAuthentication
    public void adminLogout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }

    /**
     * 首次登录时,重设密码.
     * 该接口每个用户只成功调用一次
     */
    @ApiOperation(value = "帐号首次重设密码(包括管理员和业务员)")
    @PutMapping("/active")
    @RequiresAuthentication
    @RequiresRoles(value = {ROLE_ADMIN, ROLE_SALESMAN_MANAGER, ROLE_SUPER_ADMIN}, logical = Logical.OR)
    public int activeAccount(@RequestBody @Valid ActivePasswordParam param) {
        Boolean activated = AccountHelper.getAccount().getActivated();
        Assert.isTrue(activated, ErrorCodes.ACCOUNT_ALREADY_ACTIVATED);
        return accountService.active(param.getRawPassword());
    }


    @ApiOperation(value = "修改自己密码(包括业务员/管理员)")
    @PutMapping("/changePassword")
    @RequiresAuthentication
    public int changePassword(@RequestBody @Valid PasswordModifierParam param) {
        int i = accountService.changePassword(param.getOldPassword(), param.getNewPassword());
        SecurityUtils.getSubject().logout();
        return i;
    }


    @ApiOperation(value = "验证码(图片src属性直接使用)")
    @GetMapping("/verificationCode")
    public void authCode(HttpServletResponse response, HttpServletRequest request) throws IOException {
        //String text = defaultKaptcha.createText();
        String text = translucentProducer.createText();
        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/png");
//        response.setContentType("multipart/form-data");
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, text);
        request.getSession().setAttribute(Constants.KAPTCHA_SESSION_DATE, new Date());
        BufferedImage bi = translucentProducer.createImage(text);
        try (ServletOutputStream os = response.getOutputStream()) {
            ImageIO.write(bi, "png", os);
            os.flush();
        } catch (IOException e) {
            log.error("创建验证码出错", e);
        }
    }


    @ApiOperation(value = "获取当前用户信息")
    @RequiresAuthentication
    @GetMapping("/info")
    public Account info() {
        Integer id = AccountHelper.getAccount().getId();
        return accountService.findById(id);
    }

}
